package com.prathiba.jumbledword;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.prathiba.wordrepository.WordRepository;

@Controller
public class GameController {

	@Autowired
	private Validator validator;

	@Autowired
	// this won't be initialized until spring context is loaded
	WordRepository wordRepository;

	public void setValidator(Validator validator) {
		this.validator = validator;
	}

	// used to inject DummyWordRepository from test
	public void setWordRepository(WordRepository wordRepository) {
		this.wordRepository = wordRepository;
	}

	char[] send = new char[40];
	char[] receive = new char[40];
	boolean trigger;
	boolean checkval;
	int count;
	GameScoreCalculator gameScoreCalculator = new GameScoreCalculator();

	/**
	 * Gets the word guessed by the user and checks if the user has used the
	 * same characters specified in the jumbled word and if the word is present
	 * in the valid words dictionary.
	 * 
	 * @param guessedWord
	 * @param session
	 * @return ModelAndView
	 */
	@RequestMapping(value = { "/**/guess.c" })
	public ModelAndView guess(@RequestParam("textfield") String guessedWord,
			HttpSession session) {
		LinkedList<GameUnit> gameUnits = (LinkedList<GameUnit>) session
				.getAttribute("gameUnits");
		GameUnit wordGuess = gameUnits.getLast();
		boolean isValid = validator.hasSameCharacters(
				wordGuess.getJumbledWord(), guessedWord)
				&& validator.isInDictionary(guessedWord);
		wordGuess.addGuess(new Guess(guessedWord, isValid));
		if (isValid == true) {
			count++;
		}
		ModelAndView modelAndView = new ModelAndView("home");
		modelAndView.addObject("gameUnit", wordGuess);
		return modelAndView;
	}

	/**
	 * Checks the jumbled words that are already displayed to the user from the
	 * session and displays a new jumbled word. Checks whether more jumbled
	 * words are present in the repository that have not yet been displayed to
	 * the user.If more words are present ,then a new jumbled word is displayed
	 * to the user. Otherwise end of the game has been reached. After the end of
	 * the game is reached ,it calculates and displays the score to user.
	 * 
	 * @param session
	 * @return ModelAndView
	 */
	@RequestMapping(value = { "/**/nextJumbledWord.c" })
	public ModelAndView nextJumbledWord(HttpSession session) {
		LinkedList<GameUnit> gameUnits;
		if (session.getAttribute("gameUnits") == null) {
			gameUnits = new LinkedList<GameUnit>();
		} else {
			gameUnits = (LinkedList<GameUnit>) session
					.getAttribute("gameUnits");
		}
		Set<String> wordsDisplayedToUser = getWordsDisplayedToUser(new HashSet<GameUnit>(
				gameUnits));
		Set<String> jumbledWords = wordRepository.getJumbledWords();

		JumbledWordGenerator generator = new JumbledWordGenerator();
		if (generator.isNextJumbledWordAvailable(wordsDisplayedToUser,
				jumbledWords)) {
			String jumbledWord = generator.jumbledWordNotIn(
					wordsDisplayedToUser, jumbledWords);
			GameUnit wordGuess = new GameUnit(jumbledWord);
			gameUnits.add(wordGuess);
			session.setAttribute("gameUnits", gameUnits);
			ModelAndView modelAndView = new ModelAndView("home");
			modelAndView.addObject("gameUnit", wordGuess);
			return modelAndView;
		}
		int score = gameScoreCalculator.calculateGameScore(gameUnits);
		ModelAndView modelAndView = new ModelAndView("endOfGame");
		modelAndView.addObject("score", score);
		session.invalidate();
		return modelAndView;
	}

	/**
	 * Checks and returns a set of jumbled words that has already been displayed
	 * to the user
	 * 
	 * @param gameUnits
	 * @return Set<String>
	 */
	private Set<String> getWordsDisplayedToUser(Set<GameUnit> gameUnits) {
		Set<String> wordsDisplayedToUser = new HashSet<String>();
		for (GameUnit wordGuess : gameUnits) {
			wordsDisplayedToUser.add(wordGuess.getJumbledWord());
		}
		return wordsDisplayedToUser;
	}
}